github使用说明

github使用说明

前言

什么是github,github能做什么?它是一个代码仓库,但是你可以把它当做一个远程硬盘(云盘、网盘)。和一般网盘的区别在于,它通过一个叫做git的软件进行同步,上传或下载操作,这个软件有非常强大的同步功能,甚至可以建立不同的存储分支,让同步的文件有多个不同的版本(这对代码开发来说是很有意义的)。但是,如果你不想要,不需要这个功能,也可以把它当做纯粹的免费网盘使用。

现在就有很多人,通过github来存放个人笔记,日记,博客等文档资料,在不同电脑上,只要同步一下,就能继续编辑,非常方便。这个甚至比一般的网盘要来得轻松,因为git对版本的控制更好,数据传输量更少。同步更加智能化,版本管理更加方便。

多说无益,本文介绍git的原理和使用方法,你亲自看一下是否对你有用。

一、git原理

1.1 分布式储存

git是一个分布式同步工具,简单来说,它不要求你建立一个特定的服务器,你可以在任何地方建立自己的存储仓库,不同的仓库没有地位的差异,都是平等的,这就去中心化了,所以叫分布式。

这有什么好处,比如你不需要依赖某个网盘提供商,如果它不小心倒闭了,只要你把仓库搬到另一个提供商就可以,甚至,你直接弄一台电脑放仓库也是可以的。这个理念我认为是非常有居安思危精神的。千万别过于相信网络,要给数据一个备份。

如果是传统的网盘,你需要用它的软件,下载文件到你的电脑,然后用另一家的软件,上传到另一个网盘备份,不用两天你就受不了。如果你不跟踪备份,可能网盘没通知你就把你的学习资料删除了,那你是怎么也要不回来的。相信经历过的朋友都知道。而只需用git,就能统一的管理各个仓库,轻松进行复杂的同步。

1.2 版本库 repository

也就是储存仓库,但是这个仓库不但可以放文件,还对文件的修改、删除等历史记录作跟踪,让你可以回溯到某个历史时期。这是git 最强大的功能。

为了利用好版本管理功能,要求文件类型是文本类型,最好是UTF-8编码的。

git init #在当前目录下建立仓库,将新建一个.git文件夹来存储仓库数据

1.3 添加到仓库

在当前目录新建文件,然后加入仓库,git即可维护该文件的同步管理。

git add file.txt #将当file.txt文件加入git仓库

1.4 提交到仓库

添加并不会立刻提交,也不会自动同步,这个交给用户自己判断恰当的提交时机。

git commit -m "这里写备注" #提交数据

每次提交,都要求你写一个备注,来记录你这次提交做了什么,这是个良好的习惯,因为这样你回溯历史的时候,才知道哪个版本是你的目标版本。

1.4.1 显示文件变化

当前被跟踪的文件,和仓库版本有什么差异,可以用git status 列出哪些文件改动了的文件。

如果你还想知道具体修改了什么地方,可以用git diff xxx来查看xxx文件的改动情况。

1.5 变更到不同的历史版本

这个是比较高级的功能,也许你用得上,也许用不上。首先,git reflog会显示你提交文档的版本:

#样例输出
f9adcba (HEAD -> master) HEAD@{0}: reset: moving to f9adc
9a75fd8 HEAD@{1}: reset: moving to HEAD~1
f9adcba (HEAD -> master) HEAD@{2}: commit: 测试回退功能
9a75fd8 HEAD@{3}: commit: 加了一点
781b0ad HEAD@{4}: commit: 有加了一点
55227c1 HEAD@{5}: commit: git文档修改
f2d5850 HEAD@{6}: commit (amend): ss2
ff6877d HEAD@{7}: commit (initial): ss

要跳到那个版本,使用git reset --hard f9ad,其中f9ad用具体的版本号替换。在以上样例的第一列,只需要给出几位,git就会寻找到对应版本。

当跳转到该版本,相应的文档数据会立即修改。

1.6 工作区和版本库的区别

当你在某个目录下面,创建仓库git init,该目录就是你的工作区,而具体的仓库的一些配置信息,是放在.git目录下的(可能被隐藏)。

工作区的作用就是你要同步的文件,应该放在这个目录下面,你只需要修改对应的文件,git负责其余的一切。你不需要刻意的去修改或者理会.git目录下面的内容,而应该使用git软件来输入命令。

1.7 暂存区 stage

当用git add xxx添加文件,实际上就是把文件放入暂存区。当git commit就会把暂存区的内容正式提交到某个分支(以后解释分支),并清空暂存区。

如果要撤销工作区的修改,可以用git checkout -- xxx;如果要撤销暂存区的修改,可以用git reset HEAD xxx

1.8 远程仓库

还记的我说过git是分布式的么?如果只是在自己电脑目录创建一个仓库,那就没什么意思了,现在学习怎么添加远端的仓库。

首先,申请github.com网站的账户,并申请一个仓库的使用权,然后得到一个仓库的链接地址,然后:

git remote add 仓库别名 链接 #添加远端仓库
git push -u 仓库别名 master #将本地分支master提交到仓库。-u表示关联对应分支
git remote -v #显示远程仓库情况
git pull #从远程仓库拉取最新版本

1.9 分支

git允许建立不同分支,所谓的分支,就是另一条修改文件的路线。git记录每一条路线不同的修改内容,当合并的时候会要求你对有冲突的修改内容进行选择。

git branch git #创建名为git的分支
git checkout git #切换到git分支
git branch #查看当前分支情况
git merge git #将git合并到当前分支
git branch -d git #删除git分支

创建分支后,所做任何修改,只影响当前分支,当切换分支,文件会瞬间回到另一个分支的状态下。

虽然git分支这个功能看上去很强大,又很复杂,但实际上运作非常高效,它总能按照你期望的方式去运作。因此,推荐多使用,用来划分不同的关注点也是挺好的。

一个合理的使用分支的方法是:

  1. 保持主分支不变,其他分支修改
  2. 然后将当前主分支合并到某个分支,解决冲突
  3. 最后用主分支合并该分支,更新主分区

这样就算再多人一起合作编辑,也能保证主分支是稳定可靠的。

不过,最好还是不要随便跳转分支,因为跳转分支容易导致当前数据丢失,然后还会导致很多很多的误操作。(本博客就是这样丢失了一些历史信息,╮(╯▽╰)╭!)q

1.10 储藏

特别要注意,切换分支是一个高度危险的操作!因为它会毁掉当前工作区的状态。切换分支之前,应该先提交当前修改内容到仓库。但是,如果占时无法提交,可以借助储藏功能,把当前工作区保存在一个栈表里面。

git stash #保存并清空当前工作区修改状态
git stash pop #回弹当前工作区上一个状态。
git stash list #显示储藏栈表

1.11 标签

标签对应了commit 提交版本,因为这个版本号太复杂,因此用标签名来代替,更加容易识别。也作为一个发行版本号来使用。

git tag v0.9 #当前版本命名为标签v0.9
git tag #查看当前标签
git tag -d v0.9 #删除对应标签
git push origin v0.9 #提交标签到远程仓库

二、实践

2.1 流程总结

纵观理论知识,我们可以得出一些结论:

  1. git是分布式,多仓库的,其中最直接的仓库就在当前工作目录下的.git文件,还能添加远程仓库。

  2. 工作流程是: 初始化并配置git本地仓库--》在工作区编辑文件--》提交到暂存区--》本地仓库--》远程仓库。

  3. 有回退的机制:远程仓库——pull或clone—》本地仓库--版本回溯--》当前版本工作区。

  4. 有储藏现场机制: 工作区、暂存区--stash--》储藏堆栈; 储藏堆栈--stash pop--》恢复当前工作区、暂存区。

  5. 有版本控制: 每次commit提交,就会产生一个版本记录,任何时候,只要有这个记录就能回退到该版本的状态。因此,commit之后的操作至少可以保证该版本的数据是安全的。

  6. 有分支能力: 分支对团队来说是最重要的支持能力,恰当使用分支,可以多人同时编辑,而不会产生太多数据冲突。

  7. 有些操作是危险的:如果没有提交到仓库,就切换分支,当前工作内容就可能丢失,因为切换分支并不懂得自动保存当前工作区的状态。只要是会对当前工作区产生影响的操作,都有可能影响到数据安全(如果当前工作区没有提交,有修改状态),比如拉取,同步,切换分支,版本跳转,因此这些操作之前特别要注意查看当前工作区状态,先提交,或者储藏现场。

  8. 工作区和暂存区,都是不安全的,可以视为临时数据,他们之间形成一个小型的临时版本控制机制。工作区的内容可以放到暂存区,暂存区的内容也可能回退到工作区。

2.2 配置git

2.2.1 安装git

git 官网在http://git-scm.com,下面以deepin系统为例:

apt install git #安装git
git --version #版本号2.17

2.2.2 创建本地仓库

cd ~
mkdir gittest
cd gittest
git init    #在gittest目录下创建仓库,当前工作区即是gittest

git help #查看使用说明

2.2.3 克隆远程仓库

非新项目,可以从远程仓库克隆创建。

git clone https://github.com/Anduin2017/HSharp.git cloneProj #从已有的远程仓库克隆创建名为cloneProj的本地仓库。该远程链接可以在github任意一个公开项目中获取。

2.2.4 配置本地仓库信息

git仓库的配置信息,可以存在三个地方:

  1. system 影响所有用户,文件位于/etc/gitconfig
  2. global 影响当前用户,~/.gitconfig
  3. local 影响当前仓库,.git/config
#添加用户名和邮箱信息,必备,因为每一次提交仓库都要记录当前提交人的这些信息
git config --local user.name "myname" #添加user.name的记录为myname,其中--local为默认值,可以省略
git config user.email myname@163.com #添加user.email为myname@163.com

git config --list #列出当前已经配置的内容
git config user.name #列出某项的值,即myname


2.2.5 忽略某些文件 .gitignore

如果不想某些文件被加入仓库,可以用.gitignore文件指定,内容例如:

#忽略.cpp文件和~符号结尾的文件
*.cpp
*~

2.3 检查工作区和暂存区状态

应该经常使用这个命令确认文件状态。

注意: 如果你使用编辑器来编辑,要注意当前编辑状态和当前文件状态是不同的。git是针对文件而不能知道你有没有正在编辑。如果你正在编辑,又通过git命令修改了文件,你的编辑器就会提示你原始文件已经被修改,你无法保存等异常状态。因此,你在使用git命令前,应该先把编辑状态下的文件,用编辑器保存一下。

git status #查询状态

2.4 正式进入工作

2.4.1 工作区和暂存区交互

  1. 编辑工作区上的文件,然后放到暂存区,继续编辑
  2. 如果编辑后不满意,用暂存区的内容恢复到工作区
  3. 如果满意,继续放进暂存区
#创建一个新文件,并在末尾输入内容“hello world!”
cat >>myfile.txt
hello world!
^C
#将该文件放入暂存区
git add myfile.txt
#继续编辑,并在末尾添加“hello.”
cat >>myfile.txt
hello.
^C
# 这时,就存在两个不同的版本,一个是修改前放进暂存区的"hello word!"版本,一个是工作区内的“hello word!hello."版本。
git status #遇事不决,先用这个确认状态。可以发现同一个文件,有两种状态。一种是放在暂存区的,提示让你提交;另一种是在工作区的,提示让你暂存变更。
git diff myfile.txt #确认一下文件内容的差别。显示工作区和暂存区两个同名文件的对比,如果你会看diff输出格式,就能发现差别是添加"hello."

#选择1,放弃当前修改,返回上次暂存内容
git checkout -- myfile.txt
#选择2,确认修改,放入暂存
git add myfile.txt
#git status的提示很丰富,提示上面有以上指令的使用格式

#删除文件
#如果某个文件被删除,这在git中也是一个特殊的修改
git rm xxx #删除xxx,并把删除情况告知暂存区

git rm --staged yyy #从暂存区删除yyy文件,但不影响工作区

2.4.2 暂存区和本地仓库交互

暂存区的内容并不会产生一个稳定的版本,最终要正式加入仓库,需要commit提交。

提交会要让你输入每次提交的备注,命令行下面的编辑器由git config core.editor选项控制。

git commit #向本地仓库提交暂存区的内容
git reset HEAD myfile.txt #取消暂存区内容。

git diff --staged #比较暂存区和仓库版本的不同

git commit -a -m ”备注“ #把工作区的改动全部暂存起来,然后直接提交。-a参数将缩减提交的步骤。

git log -2 #观察最近两条提交记录
git log  --pretty="%h %an,%ar:%s" #按指定格式显示记录
git log --pretty=oneline --graph #显示按分支提交结构图

apt install gitk #安装图形化显示记录的工具

2.4.3 远程仓库

git remote -v #查看远程仓库列表
git remote add remotegit https://github.com/Anduin2017/HSharp.git #添加一个远程仓库,命名为remotegit

git fetch remotegit #下载远程仓库remotegit的对象和引用

git remote show remotegit #显示远程仓库关联信息
git remote rename remotegit newname #把远程仓库命名进行修改
git remote rm newname #删除远程仓库的关联

git clone https://github.com/Anduin2017/HSharp.git clonegit #克隆生成一个完全一样的本地仓库,创建工作目录为clonegit

2.4.3.1 远程分支

远程仓库上面的分支,称为远程分支。

git remote -v #查看远端仓库情况
git remote add gitbak file:///home/user/git #加入本地另一处仓库

git fetch gitbak #下载仓库信息
git branch -av #查看所有分支,包括远端仓库
git branch --set-upstream-to=gitbak/master #当前分支关联gitbak/master分支
git pull gitbak master --allow-unrelated-histories #合并不关联的历史数据

git push cloneProj HEAD:master #提交本地分支到远端仓库

#注意:应该尽量保持本地分支名称和远程一致。

2.4.4 储藏

这个功能比较简单。

git stash #储藏当前工作区和暂存区变动
git stash pop #恢复

2.4.5 版本

每一次提交,都会产生一个版本,任何时候都可以跳转到该版本,但是版本标识是一个字符串哈希序列(sha-1 40字符哈希),不方便对外公布。

git tag #显示现有标签
git tag v1.0 #为当前版本命名标签
git show #显示HEAD关联提交对象信息
git show v1.0 #显示特定版本信息
git push origin v1.0 #向远程仓库提交标签

git commit -am"备注" #创建一个新提交"commit"对象,并改变HEAD指针指向新对象,如果头指针指向某个分支,先改变该分支指向新对象,再用HEAD指针指向该分支。简而言之,创建新版本

git reset 2341a --hard #HEAD指针调到散列为2341a开始的commit对象,即跳到该版本,--hard参数重置当先工作区和暂存区

2.4.6 分支

git中的分支,类似一个指针,一个提交(commit)类似链表中的一个节点。commit保存了父节点,和整个目录树结构,因此当分支(指针)指向某个commit,内容自然就是该节点的状态。理解这点很重要。也许你会担心每次提交都产生一个当前文件目录的快照,会不会导致存储量变得很大,实质上是不需要担心的。git以一种高效的方式进行相关记录,不管是性能还是空间,都允许你瞬间执行提交,产生新的快照。

一开始有个master的分支,有个HEAD指针,它指向master,而master指向具体的commit节点,每次提交,master都会更新到新的节点上。如果你使用某种命令移动这个指向,自然就会变更到不同的版本,这就是实现版本管理的基础。

git branch -va #显示分支情况,-a表示所有分支,包括远程分支,这个命令经常使用,因为它会显示分支的情况,类似git status显示文件情况。

git branch testbranch #基于当前分支创建一个新分支,实质不过是复制一个指针而已,效率非常高

#当你想切换到其他分支
#1. 保存正在编辑的文件
#2. 储藏现场git stash push -m "备注"
#2.2 或者提交git commit
#3. 切换分支
#为什么?因为切换分支会清空现场,你将丢失掉工作区和暂存区的改动数据
git checkout testbranch #切换到testbranch,它和此前分支上一次提交版本一模一样

git commit -m “备注” #每次提交,都会移动当前分支,指向最新的commit对象

#分支的成果最终要合并起来
git merge master #将master分支合并到当前分支
#合并过程可能会出现数据冲突,参考提示,手工选择后合并成功
git checkout master
git merge testbranch #更新master分支,一般这个分支作为默认的主分支
git branch -d testbranch #删除分支
#如果该分支新增的内容没有被合并到其他分支,就会提示让你先合并,善用git status,根据提示来操作即可。

git mergetool #调用图形界面来解决内容冲突

分支的功能并不算太复杂,但是如何设计适合自己需要的分支系统,就是一门值得思考的功课。建议master作为集成主分支,有若干分支负责实际编辑,编辑完毕合并到主分支。然后每个细分支有里程碑(用标签标注),发布版本应该选择恰当的里程碑组合,进度稍微比主分支慢。

另外,如果需要修补,可以选择在里程碑新建一个补丁分支,它需要和主分支合并,也需要和发布分支合并。

  1. master分支,负责最新版本的持续集成
  2. publish分支,负责里程碑版本的特定集成
  3. featureX分支,负责各项具体内容,并在特定版本打下里程碑标签
  4. patch分支,负责修补漏洞,选择要修复的版本,并打上修订号。因为集成是一件比较费劲的事情,所以可以选择只对特定版本进行修复。

可能用到的技术包括:

  1. 创建分支: git branch 分支名 提交对象
  2. 跳转到该分支: git checkout 分支名
  3. 编辑,保存,提交
  4. 跳转到集成分支:git checkout xxx
  5. 集成:git merge x1
  6. 打标签:git tag v1.0.0.f1
  7. 分离头指针: git checkout --detach
  8. 跳转版本:git reset --hard commit对象

集成merge的基本逻辑是:

  1. 寻找共同祖先,计算出各自不同点
  2. 让用户选择合并那些内容

因此应该采取的策略:每个分支应该尽量寻求共同祖先。那么共同祖先是怎么来的?实质以前某个merge节点(或者是分裂的初始点),否则分支怎么会有共同祖先?因此解决集成merge冲突复杂化的办法,实际是分成多次集成,也就是持续集成的意义所在。

其他使用技巧

  1. 如果显示的中文文件名变成了\344\275\277\347\224\250类似的编码格式,可以用:
    git config --global core.quotepath false
posted @ 2019-03-15 15:24  诺贝尔  阅读(897)  评论(0编辑  收藏  举报